Õppige FastAPI middleware'i põhjalikult tundma. See põhjalik juhend hõlmab kohandatud middleware'i, autentimist, logimist, veakäsitlust ja parimaid praktikaid tugevate API-de loomiseks.
Python FastAPI Middleware: Põhjalik juhend päringute ja vastuste töötlemiseks
Kaasaegses veebiarenduses on jõudlus, turvalisus ja hallatavus ülimalt tähtsad. Pythoni FastAPI raamistik on kiiresti populaarsust kogunud oma uskumatu kiiruse ja arendajasõbralike funktsioonide poolest. Üks selle võimsamaid, kuid mõnikord valesti mõistetud funktsioone on middleware. Middleware toimib olulise lülina päringute ja vastuste töötlemise ahelas, võimaldades arendajatel käivitada koodi, muuta andmeid ja jõustada reegleid enne, kui päring jõuab sihtkohta või enne, kui vastus kliendile tagasi saadetakse.
See põhjalik juhend on mõeldud ülemaailmsele arendajate publikule, alates neist, kes alles alustavad FastAPI-ga, kuni kogenud spetsialistideni, kes soovivad oma arusaamist süvendada. Me uurime middleware'i põhimõisteid, demonstreerime kohandatud lahenduste loomist ja vaatame läbi praktilised, reaalsed kasutusjuhtumid. Lõpuks olete valmis kasutama middleware'i, et luua tugevamaid, turvalisemaid ja tõhusamaid API-sid.
Mis on Middleware veebiraamistike kontekstis?
Enne koodi sukeldumist on oluline mõista kontseptsiooni. Kujutage oma rakenduse päringu-vastuse tsüklit ette kui torujuhet või konveierliini. Kui klient saadab teie API-le päringu, ei jõua see kohe teie lõpp-punkti loogikasse. Selle asemel läbib see rea töötlemisetappe. Sarnaselt, kui teie lõpp-punkt genereerib vastuse, läbib see enne kliendini jõudmist need samad etapid. Middleware komponendid ongi need samad etapid torujuhtmes.
Populaarne analoogia on sibulamudel. Sibulapea südamik on teie rakenduse äriloogika (lõpp-punkt). Iga sibula kiht, mis südamikku ümbritseb, on middleware'i osa. Päring peab läbima iga välimise kihi, et südamikku jõuda, ja vastus liigub tagasi läbi samade kihtide. Iga kiht saab sissetuleval teel päringut kontrollida ja muuta ning väljamineval teel vastust.
Sisuliselt on middleware funktsioon või klass, millel on juurdepääs päringuobjektile, vastuseobjektile ja rakenduse päringu-vastuse tsükli järgmisele middleware'ile. Selle peamised eesmärgid on järgmised:
- Koodi käivitamine: Teostage toiminguid iga sissetuleva päringu jaoks, näiteks logimine või jõudluse jälgimine.
- Päringu ja vastuse muutmine: Lisage päiseid, tihendage vastuse kehasid või teisendage andmevorminguid.
- Tsükli lühistamine: Lõpetage päringu-vastuse tsükkel varakult. Näiteks autentimise middleware võib blokeerida autentimata päringu enne, kui see jõuab sihtotstarbelisse lõpp-punkti.
- Globaalsete probleemide haldamine: Käsitlege ühiseid probleeme, nagu veakäsitlus, CORS (Cross-Origin Resource Sharing) ja seansihaldus tsentraliseeritud kohas.
FastAPI on ehitatud Starlette tööriistakomplekti peale, mis pakub ASGI (Asynchronous Server Gateway Interface) standardi tugevat rakendust. Middleware on ASGI-s põhiline kontseptsioon, muutes selle FastAPI ökosüsteemis esmaklassiliseks kodanikuks.
Lihtsaim vorm: FastAPI Middleware dekoratoriga
FastAPI pakub lihtsat viisi middleware'i lisamiseks, kasutades @app.middleware("http") dekoratorit. See sobib ideaalselt lihtsa, iseseisva loogika jaoks, mis peab käivituma iga HTTP-päringu korral.
Loome klassikalise näite: middleware, et arvutada iga päringu töötlemisaeg ja lisada see vastuse päistesse. See on jõudluse jälgimiseks uskumatult kasulik.
Näide: Protsessi-aja Middleware
Esiteks veenduge, et teil on FastAPI ja ASGI server, nagu Uvicorn, installitud:
pip install fastapi uvicorn
NĂĽĂĽd kirjutame koodi faili nimega main.py:
import time
from fastapi import FastAPI, Request
app = FastAPI()
# Define the middleware function
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
# Record the start time when the request comes in
start_time = time.time()
# Proceed to the next middleware or the endpoint
response = await call_next(request)
# Calculate the processing time
process_time = time.time() - start_time
# Add the custom header to the response
response.headers["X-Process-Time"] = str(process_time)
return response
@app.get("/")
async def root():
# Simulate some work
time.sleep(0.5)
return {"message": "Hello, World!"}
Selle rakenduse käivitamiseks kasutage käsku:
uvicorn main:app --reload
Nüüd, kui saadate päringu aadressile http://127.0.0.1:8000, kasutades tööriista nagu cURL või API klient nagu Postman, näete vastuses uut päist X-Process-Time, mille väärtus on ligikaudu 0,5 sekundit.
Koodi lahtivõtmine:
@app.middleware("http"): See dekorator registreerib meie funktsiooni HTTP middleware'i osana.async def add_process_time_header(request: Request, call_next):: Middleware funktsioon peab olema asünkroonne. See saab sissetulevaRequestobjekti ja spetsiaalse funktsioonicall_next.response = await call_next(request): See on kõige kriitilisem rida.call_nextedastab päringu torujuhtme järgmisele etapile (kas teisele middleware'ile või tegelikule teekonna operatsioonile). Sa pead seda kõnet `await`-ima. Tulemuseks on lõpp-punkti genereeritudResponseobjekt.response.headers[...] = ...: Pärast vastuse saamist lõpp-punktist saame seda muuta, antud juhul lisades kohandatud päise.return response: Lõpuks tagastatakse muudetud vastus kliendile saatmiseks.
Oma kohandatud Middleware'i loomine klassidega
Kuigi dekoratori lähenemine on lihtne, võib see muutuda piiravaks keerukamate stsenaariumide korral, eriti kui teie middleware nõuab konfiguratsiooni või peab haldama mõnda sisemist olekut. Nendel juhtudel toetab FastAPI (Starlette'i kaudu) klassipõhist middleware'i, kasutades BaseHTTPMiddleware.
Klassipõhine lähenemine pakub paremat struktuuri, võimaldab sõltuvuse süstimist selle konstruktoris ja on keeruka loogika jaoks üldiselt paremini hallatav. Põhiloogika asub asünkroonses dispatch meetodis.
Näide: Klassipõhine API võtme autentimise Middleware
Loome praktilisema middleware, mis turvab meie API. See kontrollib kindlat päist X-API-Key ja kui võti puudub või on kehtetu, tagastab see kohe 403 Forbidden veateate. See on näide päringu "lühistamisest".
Failis main.py:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.responses import Response
# A list of valid API keys. In a real application, this would come from a database or a secure vault.
VALID_API_KEYS = ["my-super-secret-key", "another-valid-key"]
class APIKeyMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
api_key = request.headers.get("X-API-Key")
if api_key not in VALID_API_KEYS:
# Short-circuit the request and return an error response
return JSONResponse(
status_code=403,
content={"detail": "Forbidden: Invalid or missing API Key"}
)
# If the key is valid, proceed with the request
response = await call_next(request)
return response
app = FastAPI()
# Add the middleware to the application
app.add_middleware(APIKeyMiddleware)
@app.get("/")
async def root():
return {"message": "Welcome to the secure zone!"}
Nüüd, kui käivitate selle rakenduse:
- Päring ilma päiseta
X-API-Key(või vale väärtusega) saab 403 olekukoodi ja JSON-veateate. - Päring koos päisega
X-API-Key: my-super-secret-keyõnnestub ja saab 200 OK vastuse.
See muster on äärmiselt võimas. Lõpp-punkti kood aadressil / ei pea teadma midagi API võtme valideerimisest; see probleem on täielikult eraldatud middleware'i kihti.
Levinud ja võimsad Middleware'i kasutusjuhtumid
Middleware on ideaalne vahend ühiste probleemide lahendamiseks. Uurime mõningaid kõige levinumaid ja mõjukamaid kasutusjuhtumeid.
1. Tsentraliseeritud logimine
Põhjalik logimine on tootmisrakenduste jaoks kohustuslik. Middleware võimaldab teil luua ühe punkti, kus saate logida olulist teavet iga päringu ja selle vastava vastuse kohta.
Näide logimise Middleware:
import logging
from fastapi import FastAPI, Request
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def logging_middleware(request: Request, call_next):
start_time = time.time()
# Log request details
logger.info(f"Incoming request: {request.method} {request.url.path}")
response = await call_next(request)
process_time = time.time() - start_time
# Log response details
logger.info(f"Response status: {response.status_code} | Process time: {process_time:.4f}s")
return response
See middleware logib sissetuleval teel päringu meetodi ja tee ning väljamineval teel vastuse olekukoodi ja kogu töötlemisaja. See annab hindamatu nähtavuse teie rakenduse liiklusesse.
2. Globaalne veakäsitlus
Vaikimisi põhjustab teie koodis käsitlemata erand 500 Internal Server Error'i, paljastades potentsiaalselt kliendile virnajäljed ja rakenduse üksikasjad. Globaalne veakäsitluse middleware saab püüda kõik erandid, logida need sisemiseks ülevaatamiseks ja tagastada standardiseeritud, kasutajasõbraliku veateate.
Näide veakäsitluse Middleware:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import logging
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def error_handling_middleware(request: Request, call_next):
try:
return await call_next(request)
except Exception as e:
logger.error(f"An unhandled error occurred: {e}", exc_info=True)
return JSONResponse(
status_code=500,
content={"detail": "An internal server error occurred. Please try again later."}
)
@app.get("/error")
async def cause_error():
return 1 / 0 # This will raise a ZeroDivisionError
Kui see middleware on paigas, ei krahhi päring aadressile /error enam serverit ega paljasta virnajälge. Selle asemel tagastab see sujuvalt 500 olekukoodi puhta JSON-kehaga, samal ajal kui täielik viga logitakse serveripoolselt arendajatele uurimiseks.
3. CORS (Cross-Origin Resource Sharing)
Kui teie esiosa rakendus pakutakse erinevast domeenist, protokollist või pordist kui teie FastAPI taustarakendus, blokeerivad brauserid päringud sama päritolu poliitika tõttu. CORS on mehhanism selle poliitika leevendamiseks. FastAPI pakub selleks otstarbeks spetsiaalset, väga konfigureeritavat `CORSMiddleware`.
Näide CORS-i konfiguratsioonist:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Define the list of allowed origins. Use "*" for public APIs, but be specific for better security.
origins = [
"http://localhost:3000",
"https://my-production-frontend.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True, # Allow cookies to be included in cross-origin requests
allow_methods=["*"], # Allow all standard HTTP methods
allow_headers=["*"], # Allow all headers
)
See on üks esimesi middleware'i osi, mille tõenäoliselt lisate igale projektile, millel on lahtiühendatud esiosa, muutes päritolupoliitikate haldamise lihtsaks ühest, kesksest asukohast.
4. GZip tihendamine
HTTP-vastuste tihendamine võib nende suurust oluliselt vähendada, mis toob kaasa klientide kiirema laadimisaja ja madalamad ribalaiuse kulud. FastAPI sisaldab `GZipMiddleware` selle automaatseks käsitlemiseks.
Näide GZip Middleware:
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
# Add the GZip middleware. You can set a minimum size for compression.
app.add_middleware(GZipMiddleware, minimum_size=1000)
@app.get("/")
async def root():
# This response is small and will not be gzipped.
return {"message": "Hello World"}
@app.get("/large-data")
async def large_data():
# This large response will be automatically gzipped by the middleware.
return {"data": "a_very_long_string..." * 1000}
Selle middleware'iga tihendatakse iga vastus, mis on suurem kui 1000 baiti, kui klient näitab, et ta aktsepteerib GZip-kodeeringut (mida teevad praktiliselt kõik kaasaegsed brauserid ja kliendid).
Täiustatud kontseptsioonid ja parimad praktikad
Kui olete middleware'iga rohkem kursis, on oluline mõista mõningaid nüansse ja parimaid praktikaid, et kirjutada puhast, tõhusat ja prognoositavat koodi.
1. Middleware'i järjekord on oluline!
See on kõige kriitilisem reegel, mida meeles pidada. Middleware'i töödeldakse järjekorras, milles see rakendusele lisatakse. Esimene lisatud middleware on "sibula" välimine kiht.
Kaaluge seda seadistust:
app.add_middleware(ErrorHandlingMiddleware) # Outermost
app.add_middleware(LoggingMiddleware)
app.add_middleware(AuthenticationMiddleware) # Innermost
Päringu voog oleks järgmine:
ErrorHandlingMiddlewaresaab päringu. See ümbritseb oma `call_next` `try...except` plokiga.- See kutsub esile `next`, edastades päringu `LoggingMiddleware`'ile.
LoggingMiddlewaresaab päringu, logib selle ja kutsub esile `next`.AuthenticationMiddlewaresaab päringu, valideerib mandaadid ja kutsub esile `next`.- Päring jõuab lõpuks lõpp-punkti.
- Lõpp-punkt tagastab vastuse.
AuthenticationMiddlewaresaab vastuse ja edastab selle üles.LoggingMiddlewaresaab vastuse, logib selle ja edastab selle üles.ErrorHandlingMiddlewaresaab lõpliku vastuse ja tagastab selle kliendile.
See järjekord on loogiline: veakäitleja on väljaspool, et saaks kinni püüda vigu mis tahes järgnevast kihist, sealhulgas teisest middleware'ist. Autentimiskihil on sügav sees, nii et me ei viitsi logida ega töödelda päringuid, mis niikuinii tagasi lükatakse.
2. Andmete edastamine funktsiooniga `request.state`
Mõnikord peab middleware edastama teavet lõpp-punkti. Näiteks võib autentimise middleware dešifreerida JWT ja eraldada kasutaja ID. Kuidas saab see kasutaja ID teekonna operatsiooni funktsioonile kättesaadavaks teha?
Vale viis on päringuobjekti otse muuta. Õige viis on kasutada objekti request.state. See on lihtne, tühi objekt, mis on ette nähtud just selleks otstarbeks.
Näide: Kasutaja andmete edastamine Middleware'ist
# In your authentication middleware's dispatch method:
# ... after validating the token and decoding the user ...
user_data = {"id": 123, "username": "global_dev"}
request.state.user = user_data
response = await call_next(request)
# In your endpoint:
@app.get("/profile")
async def get_user_profile(request: Request):
current_user = request.state.user
return {"profile_for": current_user}
See hoiab loogika puhtana ja väldib `Request` objekti nimeruumi saastamist.
3. Jõudluse kaalutlused
Kuigi middleware on võimas, lisab iga kiht väikese hulga koormust. Suure jõudlusega rakenduste puhul pidage meeles järgmisi punkte:
- Hoidke see lahjana: Middleware'i loogika peaks olema võimalikult kiire ja tõhus.
- Ole asünkroonne: Kui teie middleware peab tegema I/O toiminguid (nagu andmebaasi kontroll), veenduge, et see on täielikult `async`, et vältida serveri sündmusteahela blokeerimist.
- Kasutage eesmärgipäraselt: Ärge lisage middleware'i, mida te ei vaja. Igaüks neist lisab kõnekuhja sügavust ja töötlemisaega.
4. Teie Middleware'i testimine
Middleware on teie rakenduse loogika kriitiline osa ja seda tuleks põhjalikult testida. FastAPI `TestClient` muudab selle lihtsaks. Saate kirjutada teste, mis saadavad päringuid koos nõutud tingimustega ja ilma (nt koos kehtiva API võtmega ja ilma) ning kinnitada, et middleware käitub ootuspäraselt.
Näide APIKeyMiddleware'i testist:
from fastapi.testclient import TestClient
from .main import app # Import your FastAPI app
client = TestClient(app)
def test_request_without_api_key_is_forbidden():
response = client.get("/")
assert response.status_code == 403
assert response.json() == {"detail": "Forbidden: Invalid or missing API Key"}
def test_request_with_valid_api_key_is_successful():
headers = {"X-API-Key": "my-super-secret-key"}
response = client.get("/", headers=headers)
assert response.status_code == 200
assert response.json() == {"message": "Welcome to the secure zone!"}
Järeldus
FastAPI middleware on põhiline ja võimas tööriist igale arendajale, kes loob kaasaegseid veebi API-sid. See pakub elegantset ja korduvkasutatavat viisi ühiste probleemide lahendamiseks, eraldades need teie põhilisest äriloogikast. Iga päringu ja vastuse pealtkuulamise ja töötlemise kaudu võimaldab middleware teil rakendada tugevat logimist, tsentraliseeritud veakäsitlust, rangeid turvapoliitikaid ja jõudluse parandusi, nagu tihendamine.
Alates lihtsast @app.middleware("http") dekoratorist kuni keerukate, klassipõhiste lahendusteni on teil paindlikkus valida oma vajadustele vastav lähenemisviis. Mõistes põhimõisteid, levinud kasutusjuhtumeid ja parimaid praktikaid, nagu middleware'i tellimine ja olekuhaldus, saate luua puhtamaid, turvalisemaid ja paremini hallatavaid FastAPI rakendusi.
Nüüd on teie kord. Alustage kohandatud middleware'i integreerimist oma järgmisesse FastAPI projekti ja avage oma API disainis uus kontrolli ja elegantsi tase. Võimalused on tohutud ja selle funktsiooni valdamine muudab teid kahtlemata tõhusamaks ja tulemuslikumaks arendajaks.